/**
	Pulsar engine. Core.
	Memory managment wrappers (GCG)

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#define __PL_NO_MEMORY_MAPPING__

#include <pulsar/pulsar.h>
#include <pulsar/src/pulsar_intr.h>

#if defined(PL_MEMORY_DEBUG)

void* operator new (::size_t size, const pl_char* file, unsigned int line, const pl_char* func) throw(::std ::bad_alloc)
{
	void* p = pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, 0, file, line, func);
	if (p == NULL)
	{
		throw std::bad_alloc();
	}
	return p;
}

void* operator new [] (::size_t size, const pl_char* file, unsigned int line, const pl_char* func) throw(::std ::bad_alloc)
{
	void* p = pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, 0, file, line, func);
	if (p == NULL)
	{
		throw std::bad_alloc();
	}
	return p;
}

void* operator new (::size_t size, const ::std::nothrow_t &, const pl_char* file, unsigned int line, const pl_char* func) throw()
{
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, 0, file, line, func);
}

void* operator new [] (::size_t size, const ::std::nothrow_t &, const pl_char* file, unsigned int line, const pl_char* func) throw()
{
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, 0, file, line, func);
}

void operator delete (void* p, const pl_char* file, unsigned int line, const pl_char* func) throw (std::bad_alloc)
{
	if (p != NULL)
	{
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW, file, line, func);
	}
	return;
}

void operator delete [] (void* p, const pl_char* file, unsigned int line, const pl_char* func) throw (std::bad_alloc)
{
	if (p != NULL)
	{
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW_ARRAY, file, line, func);
	}
	return;
}

void* operator new (::size_t size, ::size_t align,const pl_char* file, unsigned int line, const pl_char* func) throw(::std ::bad_alloc)
{
	void* p = pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, align, file, line, func);
	if (p == NULL)
	{
		throw std::bad_alloc();
	}
	return p;
}

void* operator new [] (::size_t size, ::size_t align,const pl_char* file, unsigned int line, const pl_char* func) throw(::std ::bad_alloc)
{
	void* p = pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, align, file, line, func);
	if (p == NULL)
	{
		throw std::bad_alloc();
	}
	return p;
}

void* operator new (::size_t size, ::size_t align,const ::std::nothrow_t &, const pl_char* file, unsigned int line, const pl_char* func) throw()
{
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, align, file, line, func);
}

void* operator new [] (::size_t size, ::size_t align,const ::std::nothrow_t &, const pl_char* file, unsigned int line, const pl_char* func) throw()
{
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, align, file, line, func);
}

void operator delete (void* p, ::size_t align,const pl_char* file, unsigned int line, const pl_char* func) throw (std::bad_alloc)
{
	if (p != NULL)
	{
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW, file, line, func);
	}
	return;
}

void operator delete [] (void* p, ::size_t align,const pl_char* file, unsigned int line, const pl_char* func) throw (std::bad_alloc)
{
	if (p != NULL)
	{
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW_ARRAY, file, line, func);
	}
	return;
}

#endif

#if !defined(PL_MEMORY_NONE)

void* operator new (::size_t size, const ::std::nothrow_t &) throw()
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, 0, NULL, 0, PL_T(""));
#else
	return malloc(size);
#endif
}

void* operator new [] (::size_t size, const ::std::nothrow_t &) throw()
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, 0, NULL, 0, PL_T(""));
#else
	return malloc(size);
#endif
}

void* operator new (::size_t size) throw(::std ::bad_alloc)
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, 0, NULL, 0, PL_T(""));
#else
	return malloc(size);
#endif
}

void* operator new [] (::size_t size) throw(::std ::bad_alloc)
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, 0, NULL, 0, PL_T(""));
#else
	return malloc(size);
#endif
}

void operator delete (void* p, const ::std::nothrow_t &) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW, NULL, 0, PL_T(""));
#else
		free(p);
#endif
	}
	return;
}

void operator delete [] (void* p, const ::std::nothrow_t &) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW_ARRAY, NULL, 0, PL_T(""));
#else
		free(p);
#endif
	}
	return;
}

void operator delete (void* p) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW, NULL, 0, PL_T(""));
#else
		free(p);
#endif
	}
	return;
}

void operator delete [] (void* p) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW_ARRAY, NULL, 0, PL_T(""));
#else
		free(p);
#endif
	}
	return;
}

void* operator new (::size_t size, ::size_t align,const ::std::nothrow_t &) throw()
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, align, NULL, 0, PL_T(""));
#else
	return malloc_align(align,size);
#endif
}

void* operator new [] (::size_t size, ::size_t align,const ::std::nothrow_t &) throw()
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, align, NULL, 0, PL_T(""));
#else
	return malloc_align(align,size);
#endif
}

void* operator new (::size_t size,::size_t align) throw(::std ::bad_alloc)
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW, align, NULL, 0, PL_T(""));
#else
	return malloc_align(align,size);
#endif
}

void* operator new [] (::size_t size,::size_t align) throw(::std ::bad_alloc)
{
#ifdef PL_MEMORY_DEBUG
	return pl::mallocDbg(size, pl::BLOCK_TYPE_NEW_ARRAY, align, NULL, 0, PL_T(""));
#else
	return malloc_align(align,size);
#endif
}

void operator delete (void* p, ::size_t align,const ::std::nothrow_t &) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW, NULL, 0, PL_T(""));
#else
	free_align(p);
#endif
	}
	return;
}

void operator delete [] (void* p, ::size_t align,const ::std::nothrow_t &) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW_ARRAY, NULL, 0, PL_T(""));
#else
	free_align(p);
#endif
	}
	return;
}

void operator delete (void* p,::size_t align) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW, NULL, 0, PL_T(""));
#else
	free_align(p);
#endif
	}
	return;
}

void operator delete [] (void* p,::size_t align) throw()
{
	if (p != NULL)
	{
#ifdef PL_MEMORY_DEBUG
		pl::freeDbg(p, pl::BLOCK_TYPE_NEW_ARRAY, NULL, 0, PL_T(""));
#else
	free_align(p);
#endif
	}
	return;
}

#endif

void* pl::alignedMallocGcc(size_t size, size_t align)
{
	void* mallocPtr = NULL;
	void* alignedPtr = NULL;

	PL_ASSERTW(align >= 4, PL_T("Wrong align factor"));
	if (size == 0)
	{
		size++;
	}
	align = pl::max(align, 2*sizeof(void*));

	mallocPtr = malloc(size + align);
	if (mallocPtr == NULL)
	{
		return NULL;
	}

	alignedPtr = (void*)(((size_t)mallocPtr + align)& ~((size_t)(align) - 1));
	((void **)alignedPtr)[-1] = mallocPtr;
	return alignedPtr;
}

void pl::alignedFreeGcc(void *alignedPtr)
{
	if (alignedPtr != NULL)
	{
		free(((void**)alignedPtr)[-1]);
	}
	return;
}

//
// End of file 'pulsar_memory_gcc.cpp'
//
